"""
通义千问(Tongyi/Qwen) LLM提供商实现
支持阿里云通义千问API (使用OpenAI兼容接口)
"""
from typing import Dict, Any, List, Optional
from loguru import logger
import httpx
from openai import OpenAI

from storyforge.providers.base import ProviderBase


class LLMTongyiProvider(ProviderBase):
    """通义千问 LLM提供商"""
    
    def __init__(self, config: Dict[str, Any]):
        """
        初始化通义千问提供商
        
        Args:
            config: 配置字典
        """
        super().__init__(config)
        
        # 从全局配置获取默认值
        from storyforge.config import get_config
        global_config = get_config()
        llm_config = global_config.llm
        
        self.api_key = config.get("apiKey") or config.get("apiSecret")
        
        # 处理 base_url
        # 默认使用通义千问 OpenAI 兼容接口
        self.base_url = config.get("base_url") or config.get("endpoint")
        
        if self.base_url:
             # 如果用户配置了base_url，尝试智能处理
             if "dashscope.aliyuncs.com/api/v1" in self.base_url:
                 # 旧版API地址，尝试切换到兼容模式地址或用户自行承担风险
                 logger.warning("检测到配置了DashScope原生API地址，将自动切换到OpenAI兼容接口地址")
                 self.base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
             elif self.base_url.endswith("/chat/completions"):
                 self.base_url = self.base_url.replace("/chat/completions", "")
        else:
            self.base_url = "https://dashscope.aliyuncs.com/compatible-mode/v1"
            
        self.model = config.get("model", "qwen-turbo")
        
        # 从提供商配置或全局llm配置读取参数
        self.timeout = config.get("timeout") or llm_config.requestTimeout
        self.max_retries = config.get("maxRetries") or llm_config.maxRetries
        self.default_temperature = config.get("temperature") or llm_config.defaultTemperature
        self.default_max_tokens = config.get("maxOutputTokens") or llm_config.defaultMaxTokens
        
        if not self.api_key:
            raise ValueError("通义千问API密钥未配置")
            
        # 配置代理
        proxy_config = self._build_proxy_config(config)
        http_client = None
        
        if proxy_config:
            proxies = {}
            if "http" in proxy_config:
                proxies["http://"] = proxy_config["http"]
            if "https" in proxy_config:
                proxies["https://"] = proxy_config["https"]
            
            if proxies:
                http_client = httpx.Client(
                    proxies=proxies,
                    timeout=self.timeout
                )

        # 初始化 OpenAI 客户端
        self.client = OpenAI(
            api_key=self.api_key,
            base_url=self.base_url,
            timeout=self.timeout,
            max_retries=self.max_retries,
            http_client=http_client
        )
    
    def _build_proxy_config(self, config: Dict[str, Any]):
        """
        构建代理配置（优先使用提供商级别，否则使用全局配置）
        
        Args:
            config: 提供商配置字典
            
        Returns:
            代理配置字典，格式: {"http": "http://proxy:port", "https": "https://proxy:port"}，未配置返回None
        """
        from storyforge.config import get_config
        
        # 优先使用提供商级别的代理配置
        proxy_config = config.get("proxy")
        if proxy_config:
            return proxy_config
        
        # 使用全局代理配置
        global_config = get_config()
        if global_config.proxy:
            return {
                "http": global_config.proxy.http,
                "https": global_config.proxy.https
            }
        
        return None
    
    def name(self) -> str:
        """返回提供商名称"""
        return "tongyi"
    
    def generate(
        self,
        messages: List[Dict[str, str]],
        temperature: float = None,
        max_tokens: int = None,
        **kwargs
    ) -> str:
        """
        生成文本
        
        Args:
            messages: 消息列表 [{"role": "user", "content": "..."}]
            temperature: 温度参数（None则使用默认值）
            max_tokens: 最大token数（None则使用默认值）
            **kwargs: 其他参数
            
        Returns:
            生成的文本
        """
        # OpenAI兼容接口支持system message，无需特殊处理
        
        # 准备参数
        params = {
            "model": self.model,
            "messages": messages,
            "temperature": temperature if temperature is not None else self.default_temperature,
            "max_tokens": max_tokens if max_tokens is not None else self.default_max_tokens,
        }
        
        # 添加response_format（如果指定）
        response_format = kwargs.get("response_format")
        if response_format:
            params["response_format"] = response_format

        try:
            # 计算请求信息（用于日志）
            msg_head = messages[:20] if len(messages) >= 20 else messages
            msg_tail = messages[-20:] if len(messages) >= 20 else messages
            logger.debug(f"调用通义千问API: {self.model}")
            logger.debug(f"  消息长度: {len(messages)}, 温度: {params['temperature']}")
            
            import time
            start_time = time.time()
            
            response = self.client.chat.completions.create(**params)
            
            elapsed_time = time.time() - start_time
            
            content = response.choices[0].message.content
            
            # 记录使用情况
            usage = response.usage
            prompt_tokens = usage.prompt_tokens if usage else 0
            completion_tokens = usage.completion_tokens if usage else 0
            total_tokens = usage.total_tokens if usage else 0
            
            logger.info(f"通义千问API调用成功")
            logger.info(f"  模型: {self.model}")
            logger.info(f"  耗时: {elapsed_time:.2f}秒")
            logger.info(f"  输出: {len(content) if content else 0} 字符")
            logger.info(f"  Token使用: 输入={prompt_tokens}, 输出={completion_tokens}, 总计={total_tokens}")
            
            return content
            
        except Exception as e:
            logger.error(f"通义千问生成失败: {e}")
            logger.exception("API调用异常详情:")
            raise
    
    def submit(self, payload: Dict[str, Any]) -> str:
        """
        提交任务（同步调用）
        
        Args:
            payload: 任务参数
            
        Returns:
            任务ID（同步模式返回结果内容）
        """
        messages = payload.get("messages", [])
        temperature = payload.get("temperature")
        max_tokens = payload.get("max_tokens")
        
        result = self.generate(messages, temperature, max_tokens, **payload)
        return result
    
    def poll(self, external_job_id: str) -> Dict[str, Any]:
        """
        轮询任务状态（通义千问为同步调用，直接返回结果）
        
        Args:
            external_job_id: 外部任务ID（实际为生成的内容）
            
        Returns:
            状态字典
        """
        return {
            "status": "succeeded",
            "result": external_job_id
        }
